Skip to content

feat: make .sf-content-grid establish inline-size CQ scope - #649

Merged
jackgranatowski merged 4 commits into
mainfrom
claude/full-bleed-div-section-owa86g
Jul 23, 2026
Merged

feat: make .sf-content-grid establish inline-size CQ scope#649
jackgranatowski merged 4 commits into
mainfrom
claude/full-bleed-div-section-owa86g

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

.sf-content-grid now establishes an inline-size container query scope, matching the behavior of .sf-container. This ensures that .sf-grid-cols-* and .sf-bento children continue to respond to container queries when a section wrapper is switched from .sf-container to .sf-content-grid (to enable breakout/full-bleed layouts).

Previously, replacing .sf-container with .sf-content-grid silently removed the CQ scope those primitives depend on, leaving them stuck at their 1-column fallback at every width. Now the two wrappers are interchangeable.

The change is safe because:

  • .sf-content-grid's own grid tracks are fixed and never query themselves, so no self-query cycle is created
  • Inline-size containment does not affect track resolution, so full-bleed children still reach the wrapper's edges

Type

  • feat
  • fix
  • docs
  • chore / tooling

Checklist

  • Conventional Commit messages (feat:, fix:, docs:, …) — enforced by commitlint
  • npm run lint:css passes (stylelint)
  • npm run build rebuilds dist/ (bundles are git-ignored; CI rebuilds and stamps headers)
  • npm test passes (unit + Playwright e2e)
  • Version references in sync if any version-related file changed (npm run check:version)
  • LLM guide reviewed/updated if core/*.css, optional/*.css, or token-registry.json changed (npm run check:llm-guide)
  • Generated artifacts regenerated, not hand-edited (npm run check:macros, check:registry, audit:check)
  • CHANGELOG.md updated under ## [Unreleased] (for user-facing changes)
  • Breaking changes include migration docs

Notes

Three new Playwright e2e tests added to verify:

  1. .sf-content-grid establishes an inline-size query container
  2. .sf-grid-cols-* children respond to the content grid as their CQ ancestor
  3. Full-bleed reach is not shrunk by becoming a CQ container

Documentation updated to clarify that .sf-content-grid establishes a CQ scope like .sf-container, making it a drop-in replacement for breakout layouts.

https://claude.ai/code/session_01LywrnXafVz2rVBNF4TuDbi

Summary by CodeRabbit

  • Bug Fixes
    • Prevented double-guttering by ensuring full-bleed sections align correctly with their section edges inside guttered wrappers.
    • Fixed content-grid container-query behavior so responsive grid and bento components continue adapting correctly.
  • Documentation
    • Clarified that the content grid establishes an inline-size container-query scope and outlined how container-responsive primitives resolve within it.
  • Tests
    • Added automated coverage for container-query scoping and full-bleed alignment in layout scenarios.

…y with .sf-container

.sf-content-grid is the section-level wrapper you switch to when you need
breakout / full-bleed — it replaces .sf-container rather than nesting inside
it. But .sf-container was the only wrapper carrying the inline-size query
scope that .sf-grid-cols-* and .sf-bento depend on, so swapping it out
silently stranded those primitives at their 1-column fallback at every width.

Establish `container-type: inline-size` on .sf-content-grid so the two
wrappers are interchangeable. Safe re SL-034 (its tracks never query
themselves, so no self-query) and re full-bleed (inline-size containment
doesn't change track resolution — the `full` track still reaches the edges;
verified by test).

Tests: add three cases to the .sf-content-grid block — establishes CQ,
a .sf-grid-cols-* child revives, and full-bleed reach is unchanged.
Docs: note the CQ scope on the .sf-content-grid row in layout.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LywrnXafVz2rVBNF4TuDbi
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jackgranatowski, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 907cab57-f340-4e8c-84d8-253c1217a473

📥 Commits

Reviewing files that changed from the base of the PR and between 7b73a08 and 74034f3.

📒 Files selected for processing (2)
  • core/layout.css
  • tests/layout.spec.js
📝 Walkthrough

Walkthrough

.sf-content-grid now establishes an inline-size container-query scope, while guttered sections avoid double-guttering for direct content-grid children. Documentation and Playwright coverage verify responsive descendants and full-bleed edge alignment.

Changes

Content Grid Container Queries

Layer / File(s) Summary
Establish content-grid layout behavior
core/layout.css
.sf-content-grid gains container-type: inline-size, and guttered sections reset horizontal padding when directly containing a content grid.
Document container-query scope
docs/layout.md
Documentation defines query-container resolution for .sf-container, .sf-content-grid, .sf-center, and .sf-cq.
Validate responsive layout behavior
tests/layout.spec.js
Tests verify container-query scope, responsive grid columns, full-bleed widths, and guttered section edge alignment.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: codex

Suggested reviewers: claude

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: giving .sf-content-grid an inline-size container-query scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/full-bleed-div-section-owa86g

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the codex label Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/layout.spec.js (1)

839-849: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise both sides of the container-query threshold.

This test only uses a 1200px content grid on a 1200px viewport, so it verifies the wide state but not that the descendant responds to the wrapper’s own width. Add a narrow fixture (for example, 400px) and assert one column there while retaining the wide three-column assertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/layout.spec.js` around lines 839 - 849, Update the test “a
.sf-grid-cols-* child responds to the content grid as its CQ ancestor” to
exercise both container-query states: retain the existing 1200px fixture and
three-column assertion, then add a separate narrow content-grid fixture (such as
400px) and assert that its descendant resolves to one column.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/layout.spec.js`:
- Around line 839-849: Update the test “a .sf-grid-cols-* child responds to the
content grid as its CQ ancestor” to exercise both container-query states: retain
the existing 1200px fixture and three-column assertion, then add a separate
narrow content-grid fixture (such as 400px) and assert that its descendant
resolves to one column.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ce170b0f-e277-41d8-ba39-bb58c3881f1d

📥 Commits

Reviewing files that changed from the base of the PR and between 9f472c7 and eff5440.

📒 Files selected for processing (3)
  • core/layout.css
  • docs/layout.md
  • tests/layout.spec.js

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds container-type: inline-size to .sf-content-grid so that it establishes its own CQ scope, making it a drop-in replacement for .sf-container in layouts that also need breakout/full-bleed children. The CSS comment and PR notes correctly document the safety rationale (no self-query cycle; inline-size containment does not affect track resolution).

  • CSS change (core/layout.css): one declaration added before the grid track definition, with a detailed explanatory comment citing internal safety notes SL-034.
  • Tests (tests/layout.spec.js): three new Playwright e2e tests verify that containerType is inline-size, that a .sf-grid-cols-3 child responds to the content grid as its CQ ancestor, and that full-bleed reach is unchanged.
  • Docs (docs/layout.md): the .sf-content-grid row in the layout table is updated to call out the new CQ scope.

Confidence Score: 4/5

Safe to merge; the one-declaration CSS change is well-contained and the three new tests cover the key scenarios.

The CSS change is a single, carefully documented addition consistent with the unnamed CQ pattern already used by .sf-cq and .sf-fluid-cq. The PR checklist leaves CHANGELOG.md unchecked for a user-facing behaviour change, and one new test uses a split pattern inconsistent with adjacent tests — neither affects correctness.

tests/layout.spec.js has a minor style inconsistency in the new column-count assertion worth a quick look.

Important Files Changed

Filename Overview
core/layout.css Adds container-type: inline-size to .sf-content-grid; change is minimal, well-commented, and consistent with the unnamed CQ pattern used by .sf-cq and .sf-fluid-cq.
tests/layout.spec.js Three new e2e tests for the CQ scope change; the column-count assertion splits computed gridTemplateColumns by whitespace — correct for resolved 1fr values but uses .trim().split(/\s+/) where adjacent tests use the simpler .split(' '), a minor inconsistency.
docs/layout.md Single-line doc update accurately reflects the new CQ scope behaviour in the layout table.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[".sf-content-grid\n(display:grid + container-type:inline-size)"] -->|grid-column: full| B[".sf-full-bleed child\nspans full track"]
    A -->|grid-column: breakout| C[".sf-breakout child\nspans breakout track"]
    A -->|grid-column: content| D[".sf-grid-cols-3 child\nin content column"]
    A -->|CQ ancestor| E{"@container\n(min-width: 48rem)?"}
    E -->|Yes — full grid width >= 48rem| D
    D --> F["grid-template-columns:\nrepeat(3, 1fr)\n3 columns within content track"]
    E -->|No| G["grid-template-columns: none\n1-column fallback"]
Loading

Reviews (1): Last reviewed commit: "feat(layout): give .sf-content-grid an i..." | Re-trigger Greptile

Comment thread tests/layout.spec.js
Comment thread tests/layout.spec.js
claude added 2 commits July 23, 2026 05:44
Use the file's established `.split(' ')` form in the new CQ test (matching the
adjacent .sf-grid-cols-* tests) and add an inline comment explaining the
breakpoint resolves against the content grid's full width, not the child's
content-column width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LywrnXafVz2rVBNF4TuDbi
…id; doc center CQ scope

Two follow-ups from the container-system audit:

1. .sf-section--guttered × .sf-content-grid — a guttered section owns the
   inline gutter, but .sf-content-grid carries its gutter in its edge tracks,
   not padding, so the .sf-container padding reset doesn't apply to it. Left
   as-is, the section's padding boxed the grid in: content was double-guttered
   and .sf-full-bleed stopped one gutter short of the section edge. Drop the
   section's padding when a content grid is its direct child (:has()) so the
   grid spans edge-to-edge and its own tracks provide the single gutter.
   Verified: full-bleed now reaches the section edge, content sits at exactly
   one gutter.

2. Document that .sf-center intentionally does NOT establish a CQ scope (it
   stays a side-effect-free centring primitive) and that container-responsive
   children need `.sf-center .sf-cq` composition — new "Container-query scope"
   section in layout.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LywrnXafVz2rVBNF4TuDbi

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/layout.css (1)

590-602: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the .sf-container named-container contract.

.sf-content-grid only establishes an inline-size query container, while .sf-container establishes the named sf-layout container. Consumers using @container sf-layout (...) work under .sf-container but fail when the wrapper is replaced, contradicting the documented interchangeability. Make it interchangeable by assigning the same name:

-    container-type: inline-size;
+    container: sf-layout / inline-size;

Add a regression test covering @container sf-layout (...) under .sf-content-grid as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/layout.css` around lines 590 - 602, Update the .sf-content-grid
declaration to use the same named query-container contract as .sf-container,
assigning the sf-layout container name alongside its inline-size container type.
Add a regression test that verifies an `@container` sf-layout (...) rule applies
when nested under .sf-content-grid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/layout.css`:
- Around line 48-57: Restrict the `.sf-section--guttered` padding override to
sections where `.sf-content-grid` is the sole direct content child, so unrelated
siblings retain the section gutter. Update the relevant test to include a
non-grid sibling such as `#probe` and assert that its positioning still reflects
the gutter.

---

Outside diff comments:
In `@core/layout.css`:
- Around line 590-602: Update the .sf-content-grid declaration to use the same
named query-container contract as .sf-container, assigning the sf-layout
container name alongside its inline-size container type. Add a regression test
that verifies an `@container` sf-layout (...) rule applies when nested under
.sf-content-grid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 18fa0bfb-83c8-4b9d-8769-57c3044e45c2

📥 Commits

Reviewing files that changed from the base of the PR and between eff5440 and 7b73a08.

📒 Files selected for processing (3)
  • core/layout.css
  • docs/layout.md
  • tests/layout.spec.js

Comment thread core/layout.css Outdated
…the guttered reset

Two Major findings from the CodeRabbit review of the previous commit:

1. Named-container contract. .sf-container establishes the NAMED `sf-layout`
   query container; .sf-content-grid established an anonymous one, so a user's
   `@container sf-layout (…)` rule matched under the former but not the latter —
   contradicting the documented interchangeability. Give the grid the same name
   (`container: sf-layout / inline-size`). The framework's own primitives use
   anonymous `@container (…)` queries, which already matched either, so this is
   purely about honouring name-targeted user queries. Test added.

2. Guttered reset stripped sibling gutters. The `:has(> .sf-content-grid)` reset
   zeroed the section padding whenever a content grid was a direct child, so a
   non-grid sibling (heading, plain block) lost its gutter too. Restrict the
   reset to a SOLE-child content grid via
   `:not(:has(> :not(.sf-content-grid)))`; a mixed section now keeps its padding
   and behaves exactly as before the reset existed (the grid's full-bleed want
   and a sibling's gutter want are physically irreconcilable, so the ambiguous
   case is left untouched rather than guessed). Sibling-gutter test added; the
   edge-reach test's probe moved outside the section so the grid stays sole.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LywrnXafVz2rVBNF4TuDbi
@jackgranatowski
jackgranatowski merged commit 209828e into main Jul 23, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants